/*-----------------------------------
Music.h
Code by liyongchao, iwinyeah@163.com
-----------------------------------*/

#ifndef __MUSIC_H__
#define __MUSIC_H__

#include <Arduino.h>
#include "music_tables.h"

#define CH1 1
#define CH2 2
#define CH3 4
#define CH4 8

// Wave
enum {
    SINE = 0,
    SAWTOOTH = 1,
    TRIANGLE = 2,
    SQUARE = 3,
    RANDOM = 4,
};

// envelope
enum {
    NONE,
    KEYBOARD,
    HIHAT,
    FADE,
    FADE2,
    HIT,
    FADE3
};

//  Music
enum {
    M_END = 0,
    M_DELAY = 1,
    M_SLIDE = 2,
    M_FLAG = 3,
    M_VOLUME = 4,
    M_WAVE = 5,
    M_ENVELOPE = 6,
    M_REWIND = 7,
    
    M_VELOCITY_N = 0x80,
    M_NOTES_ON = 0xA0,
    M_NOTES_OFF = 0xC0,
    
    M_DELAY_N = 0xE0,   // 0..31 in single byte
    M_DELAY_1,
    M_DELAY_2,
    M_DELAY_3,
    M_DELAY_4,
    M_DELAY_5,
    M_DELAY_6,
    M_DELAY_7,
    M_DELAY_8,
    M_DELAY_9,
    M_DELAY_10,
    M_DELAY_11,
    M_DELAY_12,
    M_DELAY_13,
    M_DELAY_14,
    M_DELAY_15,
    M_DELAY_16,
    M_DELAY_17,
    M_DELAY_18,
    M_DELAY_19,
    M_DELAY_20,
    M_DELAY_21,
    M_DELAY_22,
    M_DELAY_23,
    M_DELAY_24,
    M_DELAY_25,
    M_DELAY_26,
    M_DELAY_27,
    M_DELAY_28,
    M_DELAY_29,
    M_DELAY_30,
    
    M_BAD  // 0xFF
};

// 蜂鸣器演奏类
class Music
{
public:
    /**
     * 构建函数
     * @param uint8_t pin 蜂鸣器连接引脚
     */
    Music(uint8_t pin);

    /**
     * 开始演奏MIDI序列
     * @param const uint8_t *list MIDI序列
     * @param bool force 若前一演奏序列未结束 true 强制中断，演奏新序列 false 不中断
     */
    void start(const uint8_t *list, bool force = true);

    /**
     * 推动音乐进程(将被每秒回调60次)
     */
    void step();

    /**
     * 音效开关
     */
    void turnOn(bool on);

    bool isEnable(){return enable;}
private:
    /**
     * 处理MIDI序列中下一命令
     */
    void next();

    /**
     * 复位内部变量，准备开始演奏
     */
    void reset();

    bool enable = false; // 音效开关
    bool toneStart = false; // 正在演奏

    uint8_t tonePin; // 蜂鸣器引脚
    uint8_t channel; // 当前声音通道
    uint8_t *toneList = 0; // 音效序列
    uint16_t toneIndex = 0; // 当前播放位置

    uint8_t noteNo = 0; // 音调，若>127为频率
    uint8_t noteSlide = 0; // 滑音步长
    uint8_t toneTicks = 0; // 发音时长

};

#endif
